#include <string.h>
#include <sys/time.h>

#include "key_management.h"

static PIN *pin_vector[1024];
static int pin_vector_size = 0;

static KEY *key_vector[1024];
static int key_vector_size = 0;

/**
 * 二分查找
 * @param target   目标uuid
 * @param vec_flag 0：标识要查找PIN 1：标识要查找KEY
 */
static int binarSearch(uint32_t target, int vec_flag) {
    int left = 0;
    if (!vec_flag) {
        if (!pin_vector_size) return left;
        int right = pin_vector_size - 1;
        while(left < right) {
            int mid = left + (right - left) / 2;
            if (pin_vector[mid]->uuid == target) {
                return mid;
            } else if (pin_vector[mid]->uuid < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
    } else {
        if (!key_vector_size) return left;
        int right = key_vector_size - 1;
        while(left < right) {
            int mid = left + (right - left) / 2;
            if (key_vector[mid]->uuid == target) {
                return mid;
            } else if (key_vector[mid]->uuid < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
    }

    return left;
}

KEY* getKey(uint32_t uuid) {
    int idx = binarSearch(uuid, 1);
    KEY *key = key_vector[idx];
    if (key != NULL && key->uuid == uuid)  
        return key; 
    return NULL;
}

PIN* getPIN(uint32_t uuid) {
    int idx = binarSearch(uuid, 0);
    PIN *pin = pin_vector[idx];
    if (pin != NULL &&pin->uuid == uuid)  
        return pin; 
    return NULL;
}

int setPIN(PIN *pin) {
    int idx = binarSearch(pin->uuid, 0);
    PIN *tmp_ptr = pin_vector[idx];
    if (tmp_ptr == NULL) {
        pin_vector[idx] = pin;
        ++pin_vector_size;
        return 0;
    }
    if (tmp_ptr->uuid == pin->uuid) {
        if (tmp_ptr->pin != NULL) free(tmp_ptr->pin);
        if (tmp_ptr->bd_addr != NULL) free(tmp_ptr->bd_addr);
        free(tmp_ptr);
        pin_vector[idx] = pin;
        return 0;
    }

    int t = pin_vector_size;
    while(t > idx) {
        pin_vector[t] = pin_vector[t - 1];
        t--;
    }
    pin_vector[idx + 1] = pin;
    ++pin_vector_size;

    return 0;
}

int setKEY(KEY *key) {
    int idx = binarSearch(key->uuid, 0);
    KEY *tmp_ptr = key_vector[idx];
    if (tmp_ptr == NULL) {
        key_vector[idx] = key;
        ++key_vector_size;
        return 0;
    }
    if (tmp_ptr->uuid == key->uuid) {
        if (tmp_ptr->secret != NULL) free(tmp_ptr->secret);
        if (tmp_ptr->eckey_car != NULL) free(tmp_ptr->eckey_car);
        if (tmp_ptr->eckey_mobile != NULL) free(tmp_ptr->eckey_mobile);
        free(tmp_ptr);
        key_vector[idx] = key;
        return 0;
    }

    int t = key_vector_size;
    while(t > idx) {
        key_vector[t] = key_vector[t - 1];
        t--;
    }
    key_vector[idx + 1] = key;
    ++key_vector_size;

    return 0;
}

int destroyPIN(uint32_t uuid) {
    int idx = binarSearch(uuid, 0);
    if (pin_vector[idx]->uuid != uuid)    return 0;

    PIN *tmp_ptr = pin_vector[idx];
    if (tmp_ptr->pin != NULL)   free(tmp_ptr->pin);
    if (tmp_ptr->bd_addr != NULL) free(tmp_ptr->bd_addr);
    free(tmp_ptr);
    for (int i = idx; i < pin_vector_size - 1;) {
        pin_vector[i] = pin_vector[++i];
    }
    --pin_vector_size;
    return 0;
}

int isAdmin(uint32_t uuid) {
    KEY *key = getKey(uuid);
    if (key == NULL) {
        PIN *pin = getPIN(uuid);
        if (pin != NULL && pin->flag == 0x01) {
            return 1;
        }
    } else {
        if (key->flag == 0x01)
            return 1;
    }
    return 0;
}

int keyIsValid(KEY *key) {
    if (key == NULL)   return 0;
    if (key->expiration_time == 0)  return 1;

    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_usec / 1000 < key->expiration_time ? 1 : 0;
}

int pinIsValid(PIN *pin) {
    if (pin == NULL)  return 0;
    struct timeval tv;
    gettimeofday(&tv, NULL);
    uint32_t cur_time = tv.tv_usec / 1000;
    if (cur_time >= pin->start_time && pin->end_time == 0)
        return 1;
    return cur_time >= pin->start_time && cur_time <= pin->end_time;
}


int requestIsValid(KEY *key, uint32_t time) {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_usec / 1000 > key->expiration_time;    
}

void updateRequestTime(KEY *key, uint32_t time) {
    key->recent_request = time;
}

EC_KEY* getEC_Key(uint32_t uuid, uint8_t owner) {
    KEY *key = getKey(uuid);
    if (key == NULL)    return NULL;
    if (owner == 0x00) {
        return key->eckey_mobile;
    } else if (owner == 0x01) {
        return key->eckey_car;
    }
}

int saveEC_Key(uint32_t uuid, EC_KEY* eckey, uint8_t owner) {
    KEY *key = getKey(uuid);
    if (key == NULL)    return -1;
    if (owner == 0x00) {
        if (key->eckey_mobile != NULL)  free(key->eckey_mobile);
        key->eckey_mobile = eckey;
    } else if (owner == 0x01) {
        if (key->eckey_car != NULL) free(key->eckey_car);
        key->eckey_car = eckey;
    }

    return 0;
}

uint8_t* getToken(uint8_t *pin) {
    return pin;
}

uint32_t getUid(uint8_t* pin) {
    uint16_t uuid = 0;
    memcpy(&uuid, pin, sizeof(uint16_t));
    return uuid;
}

void setSecretAndUpdateTime(uint32_t uuid, uint8_t *secret) {
    KEY *key = getKey(uuid);
    if (key != NULL) {
        if (key->secret != NULL) 
            free(key->secret);
        key->secret = secret;

        struct timeval tv;
        gettimeofday(&tv, NULL);
        updateRequestTime(key, tv.tv_usec / 1000);
    }
}

uint8_t* getSecret(uint32_t uuid) {
    KEY *key = getKey(uuid);
    if (key == NULL)    return NULL;
    return key->secret;
}
